home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / TCPSUBR.C < prev    next >
C/C++ Source or Header  |  1988-07-28  |  6KB  |  307 lines

  1. #include "global.h"
  2. #include "timer.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "internet.h"
  6. #include "tcp.h"
  7.  
  8. struct tcb *tcbs[NTCB];
  9. int16 tcp_mss = DEF_MSS;    /* Maximum segment size to be sent with SYN */
  10. int16 tcp_irtt = DEF_RTT;    /* Initial guess at round trip time */
  11.  
  12. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  13. struct tcb *
  14. lookup_tcb(conn)
  15. struct connection *conn;
  16. {
  17.     register struct tcb *tcb;
  18.     int16 hash_tcb();    
  19.  
  20.     tcb = tcbs[hash_tcb(conn)];
  21.     while(tcb != NULLTCB){
  22.         /* Yet another structure compatibility hack */
  23.         if(conn->local.address == tcb->conn.local.address
  24.          && conn->remote.address == tcb->conn.remote.address
  25.          && conn->local.port == tcb->conn.local.port
  26.          && conn->remote.port == tcb->conn.remote.port)
  27.             break;
  28.         tcb = tcb->next;
  29.     }
  30.     return tcb;
  31. }
  32.  
  33. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  34. struct tcb *
  35. create_tcb(conn)
  36. struct connection *conn;
  37. {
  38.     register struct tcb *tcb;
  39.     void tcp_timeout(),tcp_msl();
  40.     void link_tcb();
  41.  
  42.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  43.         return tcb;
  44.     if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
  45.         return NULLTCB;
  46.     ASSIGN(tcb->conn,*conn);
  47.  
  48.     tcb->mss = tcp_mss;
  49.     tcb->srtt = tcp_irtt * MSPTICK;
  50.     /* Initialize timer intervals */
  51.     tcb->timer.start = (BETA * tcb->srtt)/MSPTICK;
  52.     tcb->timer.func = tcp_timeout;
  53.     tcb->timer.arg = (char *)tcb;
  54.     tcb->rtt_timer.start = MAX_TIME; /* Largest possible value */
  55.  
  56.     link_tcb(tcb);
  57.     return tcb;
  58. }
  59.  
  60. /* Close our TCB */
  61. void
  62. close_self(tcb,reason)
  63. register struct tcb *tcb;
  64. char reason;
  65. {
  66.     struct reseq *rp,*rp1;
  67.  
  68.     stop_timer(&tcb->timer);
  69.     stop_timer(&tcb->rtt_timer);
  70.     tcb->reason = reason;
  71.  
  72.     /* Flush reassembly queue; nothing more can arrive */
  73.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  74.         rp1 = rp->next;
  75.         free_p(rp->bp);
  76.         free((char *)rp);
  77.     }
  78.     tcb->reseq = NULLRESEQ;
  79.     setstate(tcb,CLOSED);
  80. }
  81.  
  82. /* Determine initial sequence number */
  83. int32
  84. iss()
  85. {
  86.     static int32 seq;
  87.  
  88.     seq += 250000;
  89.     return seq;
  90. }
  91.  
  92. /* Sequence number comparisons
  93.  * Return true if x is between low and high inclusive,
  94.  * false otherwise
  95.  */
  96. int
  97. seq_within(x,low,high)
  98. register int32 x,low,high;
  99. {
  100.     if(low <= high){
  101.         if(low <= x && x <= high)
  102.             return 1;
  103.     } else {
  104.         if(low >= x && x >= high)
  105.             return 1;
  106.     }
  107.     return 0;
  108. }
  109. int
  110. seq_lt(x,y)
  111. register int32 x,y;
  112. {
  113.     return (long)(x-y) < 0;
  114. }
  115. int
  116. seq_le(x,y)
  117. register int32 x,y;
  118. {
  119.     return (long)(x-y) <= 0;
  120. }
  121. int
  122. seq_gt(x,y)
  123. register int32 x,y;
  124. {
  125.     return (long)(x-y) > 0;
  126. }
  127. int
  128. seq_ge(x,y)
  129. register int32 x,y;
  130. {
  131.     return (long)(x-y) >= 0;
  132. }
  133.  
  134. /* Hash a connect structure into the hash chain header array */
  135. static int16
  136. hash_tcb(conn)
  137. struct connection *conn;
  138. {
  139.     register int16 hval;
  140.  
  141.     /* Compute hash function on connection structure */
  142.     hval = hiword(conn->remote.address);
  143.     hval ^= loword(conn->remote.address);
  144.     hval ^= hiword(conn->local.address);
  145.     hval ^= loword(conn->local.address);
  146.     hval ^= conn->remote.port;
  147.     hval ^= conn->local.port;
  148.     hval %= NTCB;
  149.     return hval;
  150. }
  151. /* Insert TCB at head of proper hash chain */
  152. void
  153. link_tcb(tcb)
  154. register struct tcb *tcb;
  155. {
  156.     register struct tcb **tcbhead;
  157.     int16 hash_tcb();
  158.     char i_state;
  159.  
  160.     tcb->prev = NULLTCB;
  161.     i_state = disable();
  162.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  163.     tcb->next = *tcbhead;
  164.     if(tcb->next != NULLTCB){
  165.         tcb->next->prev = tcb;
  166.     }
  167.     *tcbhead = tcb;
  168.     restore(i_state);
  169. }
  170. /* Remove TCB from whatever hash chain it may be on */
  171. void
  172. unlink_tcb(tcb)
  173. register struct tcb *tcb;
  174. {
  175.     register struct tcb **tcbhead;
  176.     int16 hash_tcb();
  177.     char i_state;
  178.  
  179.     i_state = disable();
  180.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  181.     if(*tcbhead == tcb)
  182.         *tcbhead = tcb->next;    /* We're the first one on the chain */
  183.     if(tcb->prev != NULLTCB)
  184.         tcb->prev->next = tcb->next;
  185.     if(tcb->next != NULLTCB)
  186.         tcb->next->prev = tcb->prev;
  187.     restore(i_state);
  188. }
  189. void
  190. setstate(tcb,newstate)
  191. register struct tcb *tcb;
  192. register char newstate;
  193. {
  194.     register char oldstate;
  195.  
  196.     oldstate = tcb->state;
  197.     tcb->state = newstate;
  198.     if(tcb->s_upcall){
  199.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  200.     }
  201.     /* Notify the user that he can begin sending data */
  202.     if(tcb->t_upcall && newstate == ESTABLISHED){
  203.         (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  204.     }
  205. }
  206. /* Convert TCP header in host format into mbuf ready for transmission,
  207.  * link in data (if any), and compute checksum
  208.  */
  209. struct mbuf *
  210. htontcp(tcph,data,ph)
  211. struct tcp *tcph;
  212. struct mbuf *data;
  213. struct pseudo_header *ph;
  214. {
  215.     int16 hdrlen;
  216.     struct mbuf *rval;
  217.     register char *cp;
  218.     int16 csum;
  219.  
  220.     hdrlen = (tcph->mss != 0) ? TCPLEN + MSS_LENGTH : TCPLEN;
  221.     rval = alloc_mbuf(hdrlen);
  222.     rval->cnt = hdrlen;
  223.  
  224.     cp = rval->data;
  225.     cp = put16(cp,tcph->source);
  226.     cp = put16(cp,tcph->dest);
  227.     cp = put32(cp,tcph->seq);
  228.     cp = put32(cp,tcph->ack);
  229.     *cp++ = hdrlen << 2;    /* Offset field */
  230.     *cp++ = tcph->flags;
  231.     cp = put16(cp,tcph->wnd);
  232.     *cp++ = 0;    /* Zero out checksum field */
  233.     *cp++ = 0;
  234.     cp = put16(cp,tcph->up);
  235.  
  236.     if(tcph->mss != 0){
  237.         *cp++ = MSS_KIND;
  238.         *cp++ = MSS_LENGTH;
  239.         cp = put16(cp,tcph->mss);
  240.     }
  241.     rval->next = data;
  242.     csum = cksum(ph,rval,ph->length);
  243.     cp = &rval->data[16];    /* Checksum field */    
  244.     *cp++ = csum >> 8;
  245.     *cp = csum;
  246.  
  247.     return rval;
  248. }
  249. /* Pull TCP header off mbuf */
  250. int
  251. ntohtcp(tcph,bpp)
  252. struct tcp *tcph;
  253. struct mbuf **bpp;
  254. {
  255.     int16 hdrlen;
  256.     int16 i,optlen;
  257.  
  258.     tcph->source = pull16(bpp);
  259.     tcph->dest = pull16(bpp);
  260.     tcph->seq = pull32(bpp);
  261.     tcph->ack = pull32(bpp);
  262.     if(*bpp == NULLBUF)
  263.         /* Buffer too short to pull off header length */
  264.         return -1;
  265.     hdrlen = (pullchar(bpp) & 0xf0) >> 2;
  266.     tcph->flags = pullchar(bpp);
  267.     tcph->wnd = pull16(bpp);
  268.     (void)pull16(bpp);    /* Skip checksum */
  269.     tcph->up = pull16(bpp);
  270.     tcph->mss = 0;
  271.  
  272.     /* Check for option field. Only space for one is allowed, but
  273.      * since there's only one TCP option (MSS) this isn't a problem
  274.      */
  275.     if(hdrlen < TCPLEN)
  276.         return -1;    /* Header smaller than legal minimum */
  277.     if(hdrlen == TCPLEN)
  278.         return hdrlen;    /* No options, all done */
  279.  
  280.     if(hdrlen > len_mbuf(*bpp) + TCPLEN){
  281.         /* Remainder too short for options length specified */
  282.         return -1;
  283.     }
  284.     /* Process options */
  285.     for(i=TCPLEN; i < hdrlen;){
  286.         switch(pullchar(bpp)){
  287.         case EOL_KIND:
  288.             i++;
  289.             goto eol;    /* End of options list */
  290.         case NOOP_KIND:
  291.             i++;
  292.             break;
  293.         case MSS_KIND:
  294.             optlen = pullchar(bpp);
  295.             if(optlen == MSS_LENGTH)
  296.                 tcph->mss = pull16(bpp);
  297.             i += optlen;
  298.             break;
  299.         }
  300.     }
  301. eol:
  302.     /* Get rid of any padding */
  303.     if(i < hdrlen)
  304.         pullup(bpp,NULLCHAR,hdrlen - i);
  305.     return hdrlen;
  306. }
  307.